package skills;

import loadsave.LoadSaveable;
import loadsave.Memento;
import loadsave.loadsaveobject.Iterator;
import loadsave.loadsaveobject.LoadSaveObject;
import loadsave.loadsaveobject.LoadSaveObjectComposite;
import loadsave.loadsaveobject.LoadSavePrimitive;
import model.ModelObject;
import entity.Entity;

/**
 * The purpose of Skill is to provide a common abstract
 * interface for Skills to upgrade()  and execute().
 * Skills need an interface execute() to process when a
 * character levels up and allocates skill points.  Every
 * Skill has a combatEffect object to affect an effect on
 * entity, and therefore the common interface execute()
 * is necessary as well.  This class is required as an
 * abstract basis for skills and allows for extensibility
 * through subtyping.
 * 
 * The Skill class is responsible for conveying the
 * abstract interface for upgrade(), which is responsible
 * for incrementing the state of the Skill�s level attribute,
 * and execute(), which is responsible for creating an
 * interaction handler to handle the combatEffect
 * interactions between Entities and/or traps.  The
 * combatEffect�s are propagated through the application of
 * the influenceRadius and the Scheduler.
 * 
 * @author DangMH
 *
 */
public abstract class Skill extends ModelObject implements LoadSaveable, Cloneable {
	protected int level;
	private int mpCost;

	/**
	 * Empty constructor for loading using a Memento.
	 */
	public Skill() { }
	
	public Skill(String modelName) {
		super(modelName);
	}
	
	public Skill( String modelName, int level, int mpCost ) {
		super(modelName);
		this.level = level;
		this.mpCost = mpCost;
	}
	
	public int getMPCost() {
	    return mpCost;
	}
	
	public void upgrade() {
		++level;
	}
	
	public abstract void execute( Entity e );
	
	/**
	 * Returns the derived max range of the skill
	 */
	public int getMaxRange() {
		return ( level / 2 + 1 );
	}
	
	/*
	 * Protected get/set methods
	 */
	protected void setLevel( int level ) {
		this.level = level;
	}
	
	protected void setMPCost( int mpCost ) {
	    this.mpCost = mpCost;
	}
	
	protected int getLevel() {
		return level;
	}
	
	public Memento getMemento() {
		return new Memento() {

			public LoadSaveObject getState() {
				LoadSaveObjectComposite ret = new LoadSaveObjectComposite( "", "Skill" );
				Iterator<LoadSaveObject> iter = Skill.super.getMemento().getState().getIterator();
				for( iter.init(); iter.hasNext(); iter.next() ) {
					ret.add( iter.getCurrKey().getValue(), iter.getCurrVal());
				}
				
				ret.add( "level", new LoadSavePrimitive( "level", "int", String.valueOf( level ) ) );
				ret.add( "mpCost", new LoadSavePrimitive( "mpCost", "int", String.valueOf( mpCost ) ) );
				
				return ret;
			}

			public void restoreState(LoadSaveObject lso) {
				Skill.super.getMemento().restoreState( lso );
				
				level = Integer.valueOf( lso.get( "level" ).getValue() );
				mpCost = Integer.valueOf( lso.get( "mpCost" ).getValue() );
			}
			
		};
	}
	
	public abstract Skill clone();
}
